require "gl"
require "glu"
require "glut"
require "mathn"

#Add gl and glut namespaces in order to make porting easier
include Gl
include Glu
include Glut

#default variables
require 'benchmark'

#note: $mapdata[0][0] keeps the position for the map(-width,-height) of the real world

window =""

#mode 
$screen=1
$debug=1

#OpenGl Variable 
$viewx=0 #view point starting view, default=0
$viewy=0 #view point starting view,default=0
$s_width=800  
$s_height=600
$look_x=0.0
$look_y=0.0
$scale=1.0
$edge=20.0

#path
$mainpath="../../mapdata/"
$robotno=3
$viewcount=1

#Map Variables
$mapsize=[]
$noval=0.5
$mapdata=[]
$updatetime=1.0

#object Variables
$robotpos=[]
$startpos=[]
$vicloc=[]

#Programming function flags
$isloaded=0
$drawobject=1

#This function deals with the opengl windows settings
def init_gl_window(width ,height )

#glClearColor specifies the red, green, blue, and alpha values used by
#glClear to clear the color buffers. sets the value to be used in glClear(GL_COLOR_BUFFER_BIT)
glClearColor(0.0,0.0,0.0,0) 

glDisable(GL_DEPTH_TEST)


glMatrixMode(GL_PROJECTION) #Applies subsequent matrix operations to the projection matrix stack.
glLoadIdentity #clear old matrix
glOrtho(0,width,height, 0, 0, 1)
glMatrixMode(GL_MODELVIEW) #Applies subsequent matrix operations to the modelview matrix stack.
draw_gl_scene #draw scence
end

#This function deals with what happends when the windows reshapes itself
def reshape(width, height)
    height = 1 if height == 0 #prevent division by zero
    # Reset current viewpoint and perspective transformation
    # glViewport(Lowerright_x,Lowerright_y,width,height)
    $s_width=width
    $s_height=height
    
    #calculate the new center
    $start_x=(($s_width-(2*$edge))/2)+$edge
    $start_y=(($s_height-(2*$edge))/2)+$edge
  
    #view from 0,0
    $viewx=0
    $viewy=0
  
    glViewport($viewx, $viewy, width, height)

    glMatrixMode(GL_PROJECTION) #Applies subsequent matrix operations to the projection matrix stack.
    glLoadIdentity #Clear the Projection matrix stack 
    glOrtho(0,width,height, 0, 0, 1)
end


#output a string of text to be shown on open_gl
def output(fx,fy,fz,fstring)
  x=fx
  y=fy
  z=fz
  ostring=fstring
  i=0
  glRasterPos3f(x, y,z);
  ostring.length.times{|i|
    glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,ostring[i] );
  }
end


# This functions tells opengl what model to draw
def draw_gl_scene()
 
drawmap()
#swap buffers for display
glutSwapBuffers
  

    
end

def drawmap()
   
  glClear(GL_COLOR_BUFFER_BIT)
  #resets the model,destroying any old models
  glMatrixMode(GL_MODELVIEW)
  glLoadIdentity

 #draw map area
 glPushMatrix()
 glColor(0.3, 0.3, 0.3)
  x1 = $edge
  y1 = $edge
  x2 = $s_width-$edge
  y2 = $s_height-$edge
  glBegin(GL_QUADS)
  glVertex2f(x1, y1)
  glVertex2f(x2, y1)
  glVertex2f(x2, y2)
  glVertex2f(x1, y2)
  glEnd()
 glPopMatrix()
  
 
#log the data into the correct format    
loaddata()
loadobjdata() if ($drawobject==1)

#calculate cell size

#initiates
height_c=0
maxwidth=$xarray[0]
maxheight=$yarray[0] 

  
#calculate unitsize
maxx=$s_width-(2*$edge)
unitx=maxx/maxwidth
maxy=$s_height-(2*$edge)
unity=maxy/maxheight  

#draw the screen
glPushMatrix()   
bench=Benchmark.measure{ 
$mapdata.each_with_index { |member,y|    
  member.each_with_index{|value,x|
    if(value.to_f!=$noval)
      
   #   if(value.to_f >0.7)
  #     glColor(0.0,0.0,0.0)
  #    elsif(value.to_f<0.1)
  #    glColor(1.0,1.0,1.0)
  #    else
  #    glColor(0.3,0.3,0.3)
  #  end
    
    glColor(1.0-value.to_f,1.0-value.to_f,1.0-value.to_f)
       drawpoint(x,y,0,unitx,unity)
    end
  }
} #outer loop
glPopMatrix()

#draw the objects
if($drawobject==1)

#draw robot
$robotpos.each_with_index{|robot,index|
    glPushMatrix()
    glColor(1.0,0.0,0.0)
    drawrobot(robot[1].to_f,robot[2].to_f,0,unitx,unity)
    glPopMatrix()
}
  
#draw victims
$vicloc.each_with_index{|victim,index|
    glPushMatrix()
    glColor(1.0,0.0,0.0)
    drawvictim(victim[0].to_f,victim[1].to_f,0,unitx,unity)
    glPopMatrix()
}
      
end
    
}#bench mark
bench_array=bench.to_a
puts "benchmark draw: #{(bench_array[1].to_f+bench_array[2].to_f)}"
end


def loadobjdata()
 #if the robot postion is empty initiate the robot pos
 $robotpos=Array.new() 
 $startpos=Array.new()
 $vicloc=Array.new()
 ldpath=$mainpath+"occ_robot#{$viewcount}_obj.dat"
 puts "loading from file: #{ldpath}"
 open(ldpath,"r")do|file|
    file.each{|line|
     #turn the line into an array
     linearray=line.split(",")
     
     #log the start position
     if(line =~ /START/i )
      insertarray=[]
      insertarray<<linearray[3]<<linearray[4]
      $startpos<<insertarray
     end
        
     if(line =~ /INS/i)
     ins=Array.new(linearray)
     #get only the robot name and location
     insertarray=[]
     #get only 1,3-8 into the insert array
     #need to add width/2 and to the height/2 to the x,y because in the  
     #array of the program [-width/2][-height/2] = [0][0] in the map
     insertarray<<ins[1]<<ins[3].to_f+($xarray[0]/2).to_f<<ins[4].to_f+($yarray[0]/2).to_f<<ins[5]<<ins[6]<<ins[7]<<ins[8]
     $robotpos<<insertarray
     end
     
     #log the victims
    if(line=~/VICTIM/i)
     victim=Array.new(linearray)
     victemp=Array.new()
     victemp<<victim[2].to_f+($xarray[0]/2).to_f<<victim[3].to_f+($yarray[0]/2).to_f
     $vicloc<<victemp
   end
      
      
    }
 end
end

def loaddata()
# initiate values
$xarray=[]
$yarray=[]

#find max values
bench=Benchmark.measure{       
#load data into array
ldpath=$mainpath+"occ_robot#{$viewcount}_data.dat"
open(ldpath,"r")do|file|
 file.each_with_index{|line,index|
 if(index==0)
       #grab the size 
       $xarray<<line.split(",")[0].to_f
       $yarray<<line.split(",")[1].to_f
 end
 
 if(index==1)
 #do the prerequirements for a new map
 $tmapdata=[]
 end
 
 if (index>0)
 insertarray=line.split(",")
 insertarray.pop#remove final empty array 
 $tmapdata[$tmapdata.length]=Array.new(insertarray) if insertarray.size==$xarray[0]
 end
 
 }
 end
puts $tmapdata.size 
#if data was complete then load
$mapdata=Array.new($tmapdata) if $tmapdata.size==$yarray[0]
}#benchmark

bench_array=bench.to_a
puts "loadbench=#{(bench_array[1].to_f+bench_array[2].to_f)}" if $debug==1

end

#plots by counting the edge as 0,0
def drawpoint(x,y,z,unitx,unity)

     x1=x*(unitx.to_f)+$edge
     y1=y*(unity.to_f)+$edge
     x2 =x1+(unitx.to_f)
     y2 =y1+(unity.to_f)
     glBegin(GL_QUADS)
       glVertex2f(x1, y1)
       glVertex2f(x2, y1)
       glVertex2f(x2, y2)
       glVertex2f(x1, y2)
     glEnd()
end

#draw robot position
def drawrobot(x,y,z,unitx,unity)
      x1=x*(unitx.to_f)+$edge
      y1=y*(unity.to_f)+$edge
      glTranslated(x1,y1, 0)
	glBegin(GL_TRIANGLES);
	 glVertex2d(-(unitx*3), 0)
	 glVertex2d(unitx*3, 0)
	 glVertex2d(0,unity*6)
    glEnd();    
end

#draw victim position
def drawvictim(x,y,z,unitx,unity)
      x1=x*(unitx.to_f)+$edge
      y1=y*(unity.to_f)+$edge
      output(x1,y1,0,"x")    
end


# The idle function to handle 
def idle
    # Just redisplays the screen
    if(Time.now-$oldtime >= $updatetime)
    glutPostRedisplay
    $oldtime=Time.now
    end
end

# Keyboard handler to exit when ESC is typed
keyboard = lambda do |key, x, y|
    case(key)
      when 27
          glutDestroyWindow(window)
          exit(0)
      when ?a  # the a key, go left

      when ?d  # the d key, go right

      when ?w # the w key, go up
 
      when ?s # the s key, go down
        
      when ?+ 
        if $viewcount<$robotno
         $viewcount=$viewcount+1 
        else
          puts "no more robots"
        end
      when ?-
       if $viewcount-1>0
         $viewcount=$viewcount-1 
        else
          puts "no more robots"
        end
      when ?h
          $screen=2  if $screen==1
      when ?m
          $screen=1 if $screen==2
   end
      glutPostRedisplay
end

####################################################
#           Start initiating our code here         #
####################################################


#initiate our OpenGL
glutInit()
#Sets the display mode to be of double buffer(enables buffer swapping) with RGB mode
#and requests an alpha and depth buffer
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
#Sets the window size and start position
glutInitWindowSize($s_width, $s_height);
glutInitWindowPosition(0,0);

window=glutCreateWindow("GRID MAPPER") #creates a top level window

#glutDisplayFunc sets thedisplay callback for the current window. When GLUT determines 
#that the normal plane for the window needs to be redisplayed, the display callback 
# the window is called. GLUT determines when the display callback should be triggered
#  based on the window's redisplay state.when displaying, the method draw_gl_scence is called  
glutDisplayFunc(method(:draw_gl_scene).to_proc) 


#What method to call when the window is reshaped
glutReshapeFunc(method(:reshape).to_proc);

#What method to call while looping
glutIdleFunc(method(:idle).to_proc);

#uses the method keyboard to check for keyboardchanges
glutKeyboardFunc(keyboard);

#sets the clock
$oldtime=Time.now

#tells the program to loop
glutMainLoop();




